#!/usr/bin/env python3

import socket
import threading
import signal
import os
import datetime
import packet
import time

def now():
    return datetime.datetime.now().strftime("%F %T")

def srv_close(srv):
    srv['close'] = True
    try:
        srv['sd'].shutdown(socket.SHUT_RDWR)
    except Exception as e:
        pass
    srv['sd'].close()

def srv_join(srv):
    for t in srv['threads']:
        t.join()

def srv_create(addr, handle, **kargs):
    def connect_handle(srv):
        t = threading.currentThread()
        print("[%s]%s connect_handle start" % (now(), t))

        while not srv['close']:
            connMes = srv['sd'].recvfrom(srv['recvmax'])
            if not connMes[1]:
                break
            print("[%s]connect: " % (now()), connMes)

            cliSd = socket.socket(type=socket.SOCK_DGRAM)
            srv['handle'](cliSd, connMes, srv)
            cliSd.close()

            print("[%s]connected: " % (now()), connMes)

        print("[%s]%s connect_handle exit" % (now(), t))

    def create_socket(srv):
        srv['sd'] = socket.socket(type=socket.SOCK_DGRAM)
        srv['sd'].setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        srv['sd'].bind(srv['addr'])

    def create_workThread(srv):
        srv['threads'] = []
        for i in range(srv['climax']):
            t = threading.Thread(target=connect_handle, args=(srv, ))
            srv['threads'].append(t)

    def writePid(srv):
        name = srv['name'] if 'name' in srv else 'srv'
        f = open("/tmp/%s.pid" % name, 'w')
        f.write("%d" % (os.getpid()))
        f.close()

    srv = {}
    srv['args'] = None
    srv['recvmax'] = 1024
    srv['climax']  = 5
    srv['close'] = False
    srv['daemon'] = False
    srv.update(kargs)
    srv['addr'] = addr if type(addr) == tuple else ("0.0.0.0", addr)
    if not callable(handle):
        return None
    srv['handle'] = handle

    create_socket(srv)
    create_workThread(srv)
    writePid(srv)

    print("[%s]srv start..." % now())

    return srv

def srv_daemon(port, handle, cmd="start", **kargs):
    srv = None

    def srvExit(sig, info):
        srv_close(srv)

    def getSrvPid(name):
        try:
            pid = int(open("/tmp/%s.pid" % name).read())
        except Exception as e:
            pid = None
        return pid

    def isAlive(name):
        pid = getSrvPid(kargs['name'])
        if pid and os.path.exists("/proc/%d" % pid):
            return pid
        return None

    def srvDaemonStart(port, handle, kargs):
        if isAlive(kargs['name']):
            return None

        nonlocal srv

        if os.fork() == 0:
            os.setsid()

            f = open("/tmp/%s.log" % kargs['name'], 'a')
            os.dup2(f.fileno(), 1)

            srv = srv_create(port, handle, **kargs)
            signal.signal(signal.SIGUSR1, srvExit)
            srv_start(srv)
            srv_join(srv)

    def srvDaemonStop(name):
        pid = isAlive(kargs['name'])
        if not pid:
            return None
        os.kill(pid, signal.SIGUSR1)
        while os.path.exists("/proc/%d" % pid):
            time.sleep(0.5)

    if 'name' not in kargs:
        kargs['name'] = 'srv'

    if cmd == "stop":
        srvDaemonStop(kargs['name'])
    elif cmd == "status":
        pid = isAlive(kargs['name'])
        if pid:
            print("%s(%d) 服务器已经启动...." % (kargs['name'], pid))
        else:
            print("%s 服务器未启动" % kargs['name'])
    elif cmd == "restart":
        srvDaemonStop(kargs['name'])
        srvDaemonStart(port, handle, kargs)
    elif cmd == "start":
        srvDaemonStart(port, handle, kargs)

def srv_start(srv):
    for t in srv['threads']:
        t.start()

def cli_create(addr, connData):
    sd = socket.socket(type=socket.SOCK_DGRAM)
    if not packet.send(sd, connData, addr, packet.CONNECT):
        sd.close()
        return None

    return sd

